home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Devices / ATAErrorDetector / ATA Error Detection.c < prev    next >
Encoding:
Text File  |  1997-11-07  |  15.8 KB  |  460 lines  |  [TEXT/CWIE]

  1. /*************************************************************************
  2. **
  3. ** Apple Macintosh Developer Technical Support
  4. ** 
  5. ** Macintosh ATA Manager Sample 
  6. ** 
  7. ** by Brian Bechtel, <devsupport@apple.com>
  8. ** based on the ATA Manager Sample
  9. **  by Vinnie Moscaritolo, <vinnie@apple.com>
  10. ** Apple Developer Technical Support 
  11. ** 
  12. ** Created from as much sample code I could find.
  13. ** with much help from Gary Wilkinson, Rich Schnell and
  14. ** good ol' Martin Minow
  15. ** 
  16. ** "I never remember how a Macintosh program begins.  I just
  17. ** copy all that boilerplate from some other piece of code I
  18. ** have lying around."
  19. **      -- Bill Atkinson, paraphrased.
  20. ** 
  21. ** File:ATA Error Detection.c
  22. ** 
  23. ** Copyright © 1997 Apple Computer, Inc.
  24. ** All rights reserved.
  25. ** 
  26. ** 
  27. ** You may incorporate this sample code into your applications
  28. ** without restriction, though the sample code has been
  29. ** provided "AS IS" and the responsibility for its operation is
  30. ** 100% yours. However, what you are not permitted to do is to
  31. ** redistribute the source as "DTS Sample Code" after having
  32. ** made changes. If you're going to re-distribute the source,
  33. ** we require that you make it clear in the source that the
  34. ** code was descended from Apple Sample Code, but that you've
  35. ** made changes.
  36. **
  37. *************************************************************************/
  38.  
  39. //-----------------------------------------------------------------------
  40. #pragma mark Includes
  41. //---------------------------------------------------------------------------
  42. #include <stdio.h>
  43. #include <stdlib.h>
  44. #include <ATA.h>
  45. #ifdef __MWERKS__
  46.     #include <SIOUX.h>
  47. #endif
  48.  
  49. //----------------------------------------------------------------------------
  50. #pragma mark Defines
  51. //----------------------------------------------------------------------------
  52.  
  53. //
  54. // Identifies the bus protocol type.
  55. //
  56.  
  57. enum 
  58. {
  59.     kDevUnknown     =   0,
  60.     kDevATA         =   1,
  61.     kDevATAPI       =   2,
  62.     kDevPCMCIA      =   3
  63. };
  64.  
  65. //
  66. // Identifies the Socket type.
  67. //
  68. enum 
  69. {
  70.     kSocketUnknown      =   0,
  71.     kSocketInternal     =   1,
  72.     kSocketMediaBay     =   2,
  73.     kkSocketPCMCIA      =   3
  74. };
  75.  
  76. //------------------------------------------------------------------------------------
  77. #pragma mark Macros
  78. //------------------------------------------------------------------------------------
  79.  
  80. #define CLEAR(what) do {                        \
  81.         register Ptr        _ptr = (Ptr) &what; \
  82.         register Size       _len = sizeof what; \
  83.         for (; _len > 0; --_len)                \
  84.             *_ptr++ = 0;                        \
  85.     } while (0)
  86.  
  87. #define RETURN_IF_ERROR(_err_,_str_) if (_err_ != noErr) \
  88.     { printf(_str_, _err_); return (_err_); }
  89.  
  90. //
  91. // This is returned by the device in response to an IDENTIFY command (512 bytes).
  92. //
  93. typedef struct IdentifyBlock 
  94. {                           /* Structure of Identify data */
  95.     UInt16   Signature;  /* Word 00: Constant value      */
  96.     UInt16   NumCyls;    /* Word 01: # of cylinders (default mode) */
  97.     UInt16   RSVD0;      /* Word 02: Constant value of 0 */
  98.     UInt16   NumHds;     /* Word 03: # of heads (default mode) */
  99.     UInt16   TrkBytes;   /* Word 04: # of unformatted bytes/track */
  100.     UInt16   SecBytes;   /* Word 05: # of unformatted bytes/sector */
  101.     UInt16   NumSecs;    /* Word 06: # of sectors/track */
  102.     UInt16   VU0;        /* Word 07: Vendor unique */
  103.     UInt16   VU1;        /* Word 08: Vendor unique */
  104.     UInt16   VU2;        /* Word 09: Vendor unique */
  105.     UInt16   Serial[10]; /* Word 10-19:  Serial Number (right-justified) */
  106.     UInt16   BufType;    /* Word 20: Buffer Type */
  107.     UInt16   BufSize;    /* Word 21: Buffer size,512 byte increments */
  108.     UInt16   NumECC;     /* Word 22: # of ECC bytes */
  109.                          /* these next 2 fields are left justified */
  110.     UInt16   FirmRev[4]; /* Word 23-26:Firmware revision */
  111.     UInt16   ModelNum[20];/* Word 27-46: Model number */
  112.     UInt16   MultCmds;   /* Word 47: R/W multiple commands not impl = 0 */
  113.     UInt16   DblXferFlag;/* Word 48: Double transfer flag */
  114.     UInt16   Capabilities;/* Word 49: LBA, DMA, IORDY support indicator */
  115.     UInt16   Reserved1;  /* Word 50: Reserved */
  116.     UInt16   PIOTiming;  /* Word 51: PIO transfer timing mode */
  117.     UInt16   DMATiming;  /* Word 52: DMA transfer timing mode */
  118.     UInt16   Extension;  /* Word 53: extended info support */
  119.     UInt16   CurCylinders;/* Word 54: # of current cylinders */
  120.     UInt16   CurHeads;   /* Word 55: # of current heads */
  121.     UInt16   CurSPT;     /* Word 56: # of current sectors per track */
  122.     UInt16   CurCapacity[2];/* Word 57-58: current capacity in sectors */
  123.     UInt16   MultSectors;/* Word 59: Multiple sector setting */
  124.     UInt16   LBACapacity[2];/* Word 60-61: total sectors in LBA mode */
  125.     UInt16   SWDMA;      /* Word 62: single word DMA support */
  126.     UInt16   MWDMA;      /* Word 63: multi word DMA support */
  127.     UInt16   APIOModes;  /* Word 64: Advanced PIO Xfr mode supported */
  128.     UInt16   MDMATiming; /* Word 65: Minimum Multiword DMA Xfr Cycle */
  129.     UInt16   RDMATiming; /* Word 66: Recommended Multiword DMA Cycle */
  130.     UInt16   MPIOTiming; /* Word 67: Min PIO XFR Time W/O Flow Control */
  131.     UInt16   PIOwRDYTiming;/* Word 68:   Min PIO XFR Time with IORDY flow ctrl */
  132.     UInt16   Reserved[187];/* Word 69-255: Reserved */
  133. } IdentifyBlock;
  134.  
  135. //------------------------------------------------------------------------------------
  136. #pragma mark Prototypes
  137. //------------------------------------------------------------------------------------
  138.  
  139. Boolean     ATAManagerPresent   (void);
  140. Boolean     ATAHardwarePresent  (void);
  141. Boolean     TrapAvailable       (short theTrap);
  142. void        PrintNumVersion     (char *label, NumVersion version );
  143. OSErr       DisplayATAManagerInquiryInfo (void);
  144.  
  145. OSErr       ScanATABusses       (void);
  146. OSErr       DisplayATADriveIdentity (UInt32 deviceID );
  147. void        DumpRawBuffer       ( UInt8 *bufferPtr, int length );
  148. char*       DrvrRefToName       (short refNum);
  149. Boolean        CheckBug1(IdentifyBlock *ibPtr);
  150. Boolean        CheckBug2(IdentifyBlock *ibPtr);
  151.  
  152. // ---------------------------------------------------------------------------
  153. //
  154. // This is the mixed mode stuff needed to call the ATA manager
  155. // if you are generating CFM code (i.e. if you are compiling for
  156. // Power PC).  The 'ataManager' call is not a publicly exported
  157. // symbol in InterfaceLib.
  158. //
  159. #if GENERATINGCFM
  160.  pascal SInt16 ataManager(ataPB *pb);
  161.  
  162. #define RESULT_OFFSET(type) \
  163.      ((sizeof(type) == 1) ? 3 : ((sizeof(type) == 2) ? 1 : 0))
  164.  #define TBTrapTableAddress(trapNum) (((trapNum & 0x03FF) << 2) + 0xE00)
  165.  
  166.  pascal SInt16 ataManager(ataPB *pb)
  167.  {
  168.      #ifdef applec
  169.          #if sizeof(SInt16) > 4
  170.              #error "Result types larger than 4 bytes are not supported."
  171.          #endif
  172.      #endif
  173.      long    private_result;
  174.  
  175.      private_result = CallUniversalProc(
  176.          *(UniversalProcPtr*)TBTrapTableAddress(0xAAF1),
  177.          kPascalStackBased
  178.           | RESULT_SIZE(SIZE_CODE(sizeof(SInt16)))
  179.           | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(pb))),
  180.          pb);
  181.      return *(((SInt16*)&private_result) + RESULT_OFFSET(SInt16));
  182.  }
  183. #endif 
  184. // ---------------------------------------------------------------------------
  185. //
  186. //  Display information about the ATA Busses
  187. //
  188. OSErr       ScanATABusses (void)
  189. {
  190.     ataDrvrRegister     pb;
  191.     OSErr               status;
  192.  
  193. // Get first device ID (yes you have to do this once)
  194.     CLEAR(pb);
  195.     pb.ataPBFunctionCode    =   kATAMgrFindDriverRefnum;
  196.     pb.ataPBVers            =   kATAPBVers1;
  197.     pb.ataPBDeviceID        =   (UInt32)0x0000ffff;
  198.     status                  =   ataManager((ataPB*) &pb );
  199.  
  200. // loop through devices
  201.     for (pb.ataPBDeviceID = (UInt32) pb.ataDeviceNextID;
  202.          pb.ataPBDeviceID != 0xff;
  203.          pb.ataPBDeviceID = (UInt32) pb.ataDeviceNextID)
  204.     {           
  205.         status = ataManager((ataPB*) &pb );
  206.         RETURN_IF_ERROR(status, 
  207.             "ATA Find Driver failed with status 0x%04x\n")
  208.         
  209.         printf("\n-----------------------------------------\n\n");    
  210.         printf("Device %d %#s\n", 
  211.             pb.ataPBDeviceID, DrvrRefToName(pb.ataDrvrRefNum) );
  212.         DisplayATADriveIdentity(pb.ataPBDeviceID);
  213.     };
  214.     return (status);
  215. }
  216.  
  217. // ---------------------------------------------------------------------------
  218. void     main   (void)
  219. // ---------------------------------------------------------------------------
  220. {
  221.     OSErr           status;
  222.  
  223. #if __MWERKS__
  224.     SIOUXSettings.asktosaveonclose = false;
  225. #endif
  226.  
  227.     printf("Program to detect potential problems with SCSI disk mode\n\n");
  228.     printf("This program looks at your ATA hard disk inside your PowerBook.\n");
  229.     printf("It does not alter the disk or any data in any way.\n");
  230.     printf("See the technote \"PowerBook HD Upgrades and SCSI Disk Mode\n");
  231.     printf("Compatibility\" for details on the conditions this code tests.\n\n");
  232.     printf("Listing devices on your ATA bus ... \n\n");
  233.  
  234. // Check for ATA Hardware 
  235. // you should do this before calling the ATAManager, since some 
  236. // early ROMS could indicate an ATA manager without the proper 
  237. // HW, thus causing a crash.
  238.     if (ATAHardwarePresent() == FALSE) 
  239.     {
  240.         printf("ATA Hardware is not present on this system\n");
  241.         exit(EXIT_FAILURE);
  242.     }
  243.  
  244. // Check for ATA Manager
  245.     if (ATAManagerPresent() == FALSE) 
  246.     {
  247.         printf("ATA Manager is not present on this system\n");
  248.         exit(EXIT_FAILURE);
  249.     }
  250.         
  251. // Display ATA Device Info
  252.     status = ScanATABusses();
  253.     if (status != noErr) 
  254.     {
  255.         printf("Cannot access ATA Manager: 0x%04x\n", (int) status);
  256.         exit(EXIT_FAILURE);
  257.     }
  258. }
  259.  
  260. // ---------------------------------------------------------------------------
  261. OSErr       DisplayATADriveIdentity (UInt32 deviceID)
  262. // ---------------------------------------------------------------------------
  263. //
  264. //  Display information about the ATA Identify Info
  265. //
  266. {
  267.     ataIdentify         pb;
  268.     ataDevConfiguration pb1;
  269.     
  270.     IdentifyBlock    buffer;
  271.     OSErr           status;
  272.     Boolean            bugsExist;
  273.     UInt32            capacity;
  274.     
  275.  
  276. // Get Driver Configuration
  277.     CLEAR(pb1);
  278.     pb1.ataPBFunctionCode   =   kATAMgrGetDrvConfiguration;
  279.     pb1.ataPBVers           =   kATAPBVers2;
  280.     pb1.ataPBDeviceID       =   deviceID;
  281.     
  282.     status = ataManager((ataPB*) &pb1 );
  283.     RETURN_IF_ERROR(status, 
  284.         "ATA GetDrvConfiguration failed with status 0x%04x\n")
  285.  
  286.  
  287. // Setup Identify block;
  288.     CLEAR(pb);
  289.     pb.ataPBFunctionCode    =   kATAMgrDriveIdentify;
  290.     pb.ataPBVers            =   kATAPBVers1;
  291.     pb.ataPBDeviceID        =   deviceID;
  292.     pb.ataPBFlags           =   mATAFlagIORead + mATAFlagByteSwap ;
  293.     
  294.     if (pb1.ataDeviceType == kDevATAPI) 
  295.         pb.ataPBFlags += mATAFlagProtocol1;
  296.     
  297.     pb.ataPBTimeOut         =   100;
  298.     pb.ataPBBuffer          =   (void*) &buffer;
  299.     
  300.     status = ataManager((ataPB*) &pb );
  301.     if (noErr == status)
  302.     {
  303.         switch(pb1.ataDeviceType){        
  304.             case kDevATA:
  305.             case kDevATAPI: 
  306.                 capacity = (buffer.CurCapacity[1] << 16) | 
  307.                             buffer.CurCapacity[0];
  308.                 printf("This disk has %lu sectors of 512 bytes (0x%08lX in hexadecimal).\n", 
  309.                         capacity, capacity);
  310.                 printf("This is roughly equivalent to %lu000 bytes.", capacity/2);
  311.                 bugsExist = CheckBug1(&buffer);
  312.                 if (!bugsExist)
  313.                     bugsExist = CheckBug2(&buffer);
  314.                 if (!bugsExist)
  315.                 {
  316.                         printf("This drive may be safely used in SCSI\n");
  317.                         printf("in SCSI disk mode on a PowerBook 3400,\n");
  318.                         printf("2400, 5300, 1400, 190, or Duo 2300.\n");
  319.                 }
  320.                 break;
  321.             default:
  322.                 break;
  323.         }
  324.     }
  325.     return status;
  326. }
  327.  
  328. // ---------------------------------------------------------------------------
  329. Boolean     ATAManagerPresent   (void)
  330. // ---------------------------------------------------------------------------
  331. //
  332. // returns true if this machine has the ata manager
  333. //
  334. {
  335.         return (TrapAvailable(kATATrap));
  336. }
  337.  
  338. // ---------------------------------------------------------------------------
  339. Boolean     ATAHardwarePresent      (void)
  340. // ---------------------------------------------------------------------------
  341. //
  342. // returns true if this machine has ata hardware
  343. //
  344. {
  345.     UInt16  configFlags;
  346.  
  347.     // Hardware configuration flags
  348.     configFlags = LMGetHWCfgFlags();
  349.     
  350.     return (configFlags & 0x0080);
  351. }
  352.  
  353. //------------------------------------------------------------------------------------
  354. #pragma mark -
  355.  
  356. #define NumToolboxTraps() (                             \
  357.         (NGetTrapAddress(_InitGraf, ToolTrap)           \
  358.                 == NGetTrapAddress(0xAA6E, ToolTrap))   \
  359.             ? 0x200 : 0x400                             \
  360.     )
  361. #define GetTrapType(theTrap) (                          \
  362.         (((theTrap) & 0x800) != 0) ? ToolTrap : OSTrap  \
  363.     )
  364.  
  365. // ---------------------------------------------------------------------------
  366. Boolean     TrapAvailable       (short theTrap)
  367. // ---------------------------------------------------------------------------
  368. // (see Inside Mac VI 3-8)
  369. {
  370.         TrapType                trapType;
  371.         
  372.         trapType = GetTrapType(theTrap);
  373.         if (trapType == ToolTrap) 
  374.         {
  375.             theTrap &= 0x07FF;
  376.             if (theTrap >= NumToolboxTraps())
  377.                 theTrap = _Unimplemented;
  378.         }
  379.         return (
  380.             NGetTrapAddress(theTrap, trapType)
  381.             != NGetTrapAddress(_Unimplemented, ToolTrap)
  382.             );
  383. }
  384.  
  385. // ---------------------------------------------------------------------------
  386. char*       DrvrRefToName(short refNum)
  387. // ---------------------------------------------------------------------------
  388. //
  389. //  lookup driver name in table
  390. //
  391.  
  392. {
  393.         AuxDCEHandle*       UTable  = 
  394.             (AuxDCEHandle*) LMGetUTableBase();
  395.         DCtlPtr             dctl;
  396.         Ptr                 p;  
  397.         
  398.         if(!refNum)     
  399.             return ((char*) "\p<none>");
  400.  
  401.         dctl = (DCtlPtr) *UTable[~refNum];
  402.         p    =  dctl->dCtlDriver;
  403.         if( dctl->dCtlFlags  & 0x0040) 
  404.             p = (void*) *p;
  405.  
  406.         return  ( p?(char*) (p+18):(char*)"\p-Purged-");
  407. }
  408.  
  409.  
  410. // ---------------------------------------------------------------------------
  411. Boolean CheckBug1(IdentifyBlock *ibPtr)
  412. // ---------------------------------------------------------------------------
  413. //
  414. //  Check for the first of the two bugs.  If a drive reports a capacity that
  415. //  is greater than 4 gigabytes, then you should not use that drive in SCSI
  416. //  disk mode on a 190/2300/1400/5300/3400/2400.  Return false if no bug
  417. //  conditions found.
  418. //
  419. {
  420.     UInt32            capacity;
  421.     Boolean            result = false;    // assume no bug    
  422.  
  423.     capacity = (ibPtr->CurCapacity[1] << 16) | 
  424.                 ibPtr->CurCapacity[0];
  425.     if (capacity >= (UInt32)0x00800000)
  426.     {
  427.         printf("\n\n******************************************\n");    
  428.             printf("* Warning! This drive is too large to be *\n");
  429.             printf("* used in SCSI disk mode on a PowerBook  *\n");
  430.             printf("* 3400, 2400, 5300, 1400, 190, or 2300!  *\n");
  431.             printf("******************************************\n\n");
  432.             result = true;
  433.     }
  434.     return result;
  435. }
  436.  
  437. // ---------------------------------------------------------------------------
  438. Boolean CheckBug2(IdentifyBlock *ibPtr)
  439. // ---------------------------------------------------------------------------
  440. //
  441. //  Check for the second of the two bugs.  If a drive reports a capacity that
  442. //  has a lower word with the top bit set, the last 16 Mb of that drive won't
  443. //  work correctly on the 5300/190/1400/2300. Return false if no bug
  444. //  conditions found.
  445. //
  446. {
  447.     Boolean            result = false;    // assume no bug
  448.  
  449.     if (ibPtr->CurCapacity[0] & 0x8000)
  450.     {
  451.         printf("\n\n******************************************\n");    
  452.             printf("* Warning! This drive should not be used *\n");
  453.             printf("* in SCSI disk mode on a PowerBook 5300, *\n");
  454.             printf("* 1400, 190, or Duo 2300!                *\n");
  455.             printf("* This drive is safe on a 3400 or 2400.  *\n");
  456.             printf("******************************************\n");
  457.             result = true;  
  458.     }
  459.     return result;
  460. }